package org.faesa.masterSlave.master;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.rmi.RemoteException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.faesa.masterSlave.common.DecodeText;

class SlaveDecodeTextTask implements Runnable {
	private static String encodedText;
	private static String findKey;
	private static ExecutorService threadPool;
	private static ArrayBlockingQueue<String> blockingQueue;	
	
	static {
		SlaveDecodeTextTask.threadPool = Executors.newCachedThreadPool();
		SlaveDecodeTextTask.blockingQueue = new ArrayBlockingQueue<String>(10);
	}
	
	static void newKey(String key) throws InterruptedException {
		SlaveDecodeTextTask.blockingQueue.put(key);
	}
	public static String getEncodedText() {
		return encodedText;
	}
	public static void setEncodedText(String encodedText) {
		SlaveDecodeTextTask.encodedText = encodedText;
	}
	public static String getFindKey() {
		return findKey;
	}
	public static void setFindKey(String findKey) {
		SlaveDecodeTextTask.findKey = findKey;
	}

	private SlaveEntryPoint entryPoint;
	private Lock lock;
	private Condition awaitingCondition;
	private boolean awaiting;
	private Future<?> future;
	
	public SlaveDecodeTextTask(SlaveEntryPoint entryPoint) {
		if (entryPoint == null) {
			throw new NullPointerException("entryPoint");
		}
		this.entryPoint = entryPoint;
		this.awaiting = false;
		this.future = null;
		this.lock = new ReentrantLock();
		this.awaitingCondition = this.lock.newCondition();
	}
	
	public void executeMe() {
		this.future = SlaveDecodeTextTask.threadPool.submit(this);
	}
	public void cancel() {
		this.lock.lock();
		try {
			try {
				while (!this.awaiting) {
					this.awaitingCondition.await();
				}
			} catch (InterruptedException e) { }

			this.future.cancel(true);
		}
		finally {
			this.lock.unlock();
		}
	}
	
	
	@Override
	public void run() {
		DecodeText decodeText = this.entryPoint.getDecodeText();
		try {
			while (!this.future.isCancelled() && !this.future.isDone()) {
				this.lock.lock();
				try {
					this.awaiting = true;
					this.awaitingCondition.signal();
				}
				finally {
					this.lock.unlock();
				}
				
				String key = SlaveDecodeTextTask.blockingQueue.take();
				
				this.lock.lock();
				try{
					this.awaiting = false;
				}
				finally {
					this.lock.unlock();
				}
				
				try {
					System.out.print("sending encoded message to " + this.entryPoint.getId() + " with key " + key + "...");
					String decoded = decodeText.decodeText(SlaveDecodeTextTask.encodedText, key, SlaveDecodeTextTask.findKey);
					if (decoded != null && !decoded.isEmpty()) {
						try {
							File dir = new File("resultados");
							dir.mkdirs();
							File file = new File(dir.getAbsoluteFile() + "\\decifrado - " + key + ".txt");						
							file.createNewFile();
							
							BufferedWriter out = new BufferedWriter(new FileWriter(file.getAbsolutePath()));  
							out.write(decoded);
							out.close();
							
							System.out.println("created file " + file.getAbsolutePath());
						} catch (IOException ioex) {
							System.out.println("fail to create file");
						}
					}
					else {
						System.out.println("wrong");
					}
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		catch (InterruptedException ex) {
			System.out.println("slave task thread for " + this.entryPoint.getId().toString() + " interrupted");
		}
	}
}
